<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 代理和反射是ES6中新增的API，理解两个API用处很多
        // 比如vue中数据绑定实现原理就是调用Object.definePeoperty,而Proxy其实就是Object.definePeoperty的语法糖


        // Proxy:
        // 个人理解：不直接操作对象，而是通过操作对象的代理对象来操作对象
        // 看下面代码，我们获取age值得时候不是直接通过user.age获取，而是先new一个user的代理对象p，
        // 通过这个p去获取age,好处是可以在设置和获取属性时进行一些额外的操作，比较类似于装饰器的作用
        // var user = {
        //     name: 'iwen',
        //     age: 18
        // }
        // var p = new Proxy(user, {
        //     get(target, key) {
        //         console.log(`get ${key}`);
        //         return target[key]
        //     },
        //     set(target, key, value) {
        //         console.log(`set ${key}`)
        //         target[key] = value
        //     }
        // })
        // p.age;
        // p.age = 20;



        // var options = {
        //     data() {
        //         return {
        //             name: 'iwen',
        //             age: 18
        //         }
        //     }
        // }
        // var vm = new Proxy(options, {
        //     get(target, key) {
        //         return target.data()[key]
        //     },
        //     set(target, key, val) {
        //         target.data()[key] = val
        //     }
        // })
        // vm.age;


        // Reflect
        // 个人理解，其实就是换一种更优雅的方式来操作对象
        // 比如判断对象中是否有某个属性
        // 'age' in obj;//传统做法
        // Reflect.has(obj,'age');//Reflect做法
        // 比如apply使用（bar为一个函数）
        // bar.apply(obj, 'iwen'); // 传统做法
        // Reflect.apply(bar, obj, [1, 2, 3]); // Reflect做法


        // 练习：一个项目中window上绑定了很多事件，在不修改项目原有代码的基础上如何获得window上绑定的事件？
        /**
         * @desc  获取window上所有绑定的事件
         */

        // var getAllWindowEvent = function(w) {
        //     w.listLenster = new Set();
        //     var _cache = w.addEventListener;
        //     var handler = {
        //         apply(target, thisBindding, args) {
        //             listLenster.add(args[0]);
        //             Reflect.apply(_cache, w, args);
        //         }
        //     }
        //     w.addEventListener = new Proxy((event, fn) => {}, handler)
        // }
        // getAllWindowEvent(window);

        // //  这里的window.addEventListener已经是代理对象了
        // window.addEventListener('click', function() {
        //     console.log('click');
        // })
        // window.addEventListener('resize', function() {
        //     console.log('resize');
        // })
        // console.log(...listLenster);



        // Reflect常见方法
        // Reflect.apply
        // Reflect.construct
        // Reflect.defineProperty
        // Reflect.deleteProperty
        // Reflect.enumerata //废弃的
        // Reflect.get
        // Reflect.has
        // Reflect.ownKeys
        // Reflect.set


        // API
        // Reflect.set(target, propertyKey, value): 设置对象target的属性propertyKey的值为value，等同于给对象的属性赋值
        // Reflect.get(target, propertyKey): 读取对象target的属性propertyKey， 等同于读取对象的属性值
        // Reflect.apply(target, thisArgument, argumentsList)： 调用一个指定的函数， 并绑定this和参数列表。 等同于函数调用
        // Reflect.deleteProperty(target, propertyKey)： 删除一个对象的属性
        // Reflect.defineProperty(target, propertyKey, attributes)： 类似于Object.defineProperty， 不同的是如果配置出现问题， 返回false而不是报错
        // Reflect.construct(target, argumentsList)： 用构造函数的方式创建一个对象
        // Reflect.has(target, propertyKey): 判断一个对象是否拥有一个属性



        // const obj = {
        //     a: 1,
        //     b: 2
        // }

        // // Reflect.set(obj,'a',10);
        // // 等效于
        // // obj.a = 10;
        // console.log(Reflect.get(obj, 'a'));
        // // 等效于
        // console.log(obj.a);


        // function method(a, b) {
        //     console.log('method', a, b);
        // }
        // Reflect.apply(method, null, [3, 4]);
        // // 等效于
        // // method(3,4)
        // const obj = {
        //     a: 1,
        //     b: 2
        // }
        // Reflect.deleteProperty(obj, 'a');
        // // 等效于
        // // delete obj.a



        // Proxy代理
        // 代理：提供了修改底层实现的方式，代理不占空间

        // 代理一个对象
        // target: 目标对象
        // handler: 是一个普通对象，其中重写底层实现
        // 返回一个代理对象
        // new Proxy(target,handler)

        const obj = {
            a: 1,
            b: 2
        }
        const proxy = new Proxy(obj, {
            set(target, propertyKey, value) {
                // console.log(target,prototypeKey,value);
                // target[propertyKey] = value;//原来的设置值
                Reflect.set(target, prototypeKey, value);
            },
            get(target, prototypeKey) {
                if (Reflect.has(target, prototypeKey)) {
                    return Reflect.get(target, prototypeKey);
                } else {
                    return -1;
                }
            },
            has(target, propertyKey) {
                return false;
            }
        })
        console.log(proxy);
        proxy.a = 10;
        console.log(proxy.a);
        console.log(proxy.d); //不存在返回-1
        console.log('a' in proxy);
    </script>
</body>

</html>